#include "platform.h"
#include "../mds/sys/string.h"

static
char * ocl_platform_string(cl_platform_id   id,
						   cl_platform_info name)
{
	char  *s      = NULL;
	size_t length = 0;
	
	if( CL_SUCCESS != ( ocl_errno = clGetPlatformInfo(id, name, 0, NULL, &length ) ) )
	{
		return NULL;
	}
	assert(length>0);
	
	if( NULL == ( s = mds_string_create( length-1 ) ) )
	{
		return NULL;
	}
	
	if( CL_SUCCESS != ( ocl_errno =  clGetPlatformInfo(id, name, length, s, NULL) ) )
	{
		mds_string_delete(s);
		return NULL;
	}
	
	return s;
}


int ocl_platform_load( cl_platform_id id, ocl_platform *platform  )
{
	static const char fn[] = "[ocl_platform_load]";
	assert( platform );
	
	/*-----------*/
	/* clean up */
	/*---------*/
	ocl_errno = CL_SUCCESS;
	memset( platform, 0, sizeof( *platform ) );
	
	/*---------------*/
	/* store the id */
	/*-------------*/
	platform->id = id;
	
	/*---------------------*/
	/* probe the #devices */
	/*-------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s Query #devices\n", fn );
	
	if( CL_SUCCESS != ( ocl_errno = clGetDeviceIDs( id,  CL_DEVICE_TYPE_ALL, 0, NULL, & platform->num_devices ) ) )
	{
		goto ERROR;
	}
	
	/*--------------------------*/
	/* allocate the devices_id */
	/*------------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s CALLOC(cl_device_id,%u)\n", fn, platform->num_devices );
	if( NULL == (platform->devices_id = MDS_CALLOC_AS(cl_device_id,platform->num_devices) ) )
	{
		goto ERROR;
	}
	
	/*----------------------*/
	/* fill the devices_id */
	/*--------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s Read devices_id\n", fn);
	if( CL_SUCCESS != ( ocl_errno = clGetDeviceIDs( id, CL_DEVICE_TYPE_ALL, platform->num_devices, platform->devices_id, NULL) ) )
	{
		goto ERROR;
	}
	
	/*---------------------------*/
	/* allocate the ocl_devices */
	/*-------------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s CALLOC(ocl_device,%u)\n", fn, platform->num_devices  );
	if( NULL == (platform->devices = MDS_CALLOC_AS(ocl_device,platform->num_devices) ) )
	{
		goto ERROR;
	}
	
	/*-------------------------*/
	/* create the ocl_devices */
	/*-----------------------*/
	if( ocl_logfile ) fprintf( ocl_logfile, "%s ==> Load each device...\n", fn );
	for( platform->reserved = 0; platform->reserved < platform->num_devices; platform->reserved++ )
	{
		if( ocl_logfile ) fprintf( ocl_logfile, "%s -------- device %u --------\n", fn, platform->reserved );
		if( ocl_device_load(platform->devices_id[ platform->reserved ],
							&  platform->devices[ platform->reserved  ] ) < 0 )
		{
			goto ERROR;
		}
		
	}
	if( ocl_logfile ) fprintf( ocl_logfile, "%s ==> Done\n", fn );
	
	/*--------------------------------*/
	/* extract the other information */
	/*------------------------------*/
#define OCL_PLATFORM_INFO_STRING(FIELD) \
if( NULL == (platform->FIELD = ocl_platform_string( platform->id, CL_PLATFORM_##FIELD)  ) ) goto ERROR; else \
if( ocl_logfile ) fprintf( ocl_logfile, "%s %-12s= '%s'\n", fn, #FIELD, platform->FIELD )
	
	OCL_PLATFORM_INFO_STRING(VERSION);
	OCL_PLATFORM_INFO_STRING(NAME);
	OCL_PLATFORM_INFO_STRING(VENDOR);
	
	return 0;
	
ERROR:
	ocl_platform_quit( platform );
	return -1;
}

void ocl_platform_quit( ocl_platform *platform )
{
	static const char fn[] = "[ocl_platform_free]";
	assert( platform );
	if( ocl_logfile ) fprintf( ocl_logfile, "%s\n", fn);
	mds_string_delete( platform->VENDOR  );
	mds_string_delete( platform->NAME    );
	mds_string_delete( platform->VERSION );
	
	
	if( platform->devices)
	{
		while( platform->reserved > 0 )
		{
			ocl_device_quit( & platform->devices[ --(platform->reserved) ] );
		}
		MDS_FREE_AS( ocl_device, platform->devices, platform->num_devices);
	}
	
	if( platform->devices_id ) 
		MDS_FREE_AS( cl_platform_id, platform->devices_id, platform->num_devices);
	
	memset( platform, 0, sizeof( *platform ) );
}
